#include "stdafx.h"
#include "Topology.h"

Topology::Topology()
{
}

Topology::~Topology()
{
}

int Topology::InsertCustomerProvider(As *pCustomer, As *pProvider)
{
	pCustomer->AddProvider(pProvider);
	pProvider->AddCustomer(pCustomer);
	Graph::Insert(static_cast<Vertex*> (pCustomer));
	Graph::Insert(static_cast<Vertex*> (pProvider));
	return 1;
}

int Topology::InsertPeerToPeer(As *pPeerA, As *pPeerB)
{
	pPeerA->AddPeer(pPeerB);
	pPeerB->AddPeer(pPeerA);
	Graph::Insert(static_cast<Vertex*> (pPeerA));
	Graph::Insert(static_cast<Vertex*> (pPeerB));
	return 2;
}

Set<As*>* Topology::GetAss()
{
	//return Set<As*>(Vertices.begin(), Vertices.end());
	Set<As*>* result = new Set<As*>();
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		result->insert((As*)(Vertices[i]));
	}
	return result;
}

Vector<As*>* Topology::GetOrderedAss()
{
	//return Set<As*>(Vertices.begin(), Vertices.end());
	Vector<As*>* result = new Vector<As*>();
	As* attacker = 0;
	As* victim = 0;
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		if (Vertices[i]->GetName() == ATTACKER_ID)
		{
			attacker = static_cast<As*>(Vertices[i]);
		}
		else if (Vertices[i]->GetName() == VICTIM_ID)
		{
			victim = static_cast<As*>(Vertices[i]);
		}
		else
		{
			result->push_back(static_cast<As*>(Vertices[i]));
		}
	}

	return result;
}

void Topology::InitializeOrderedAss(Vector<As*>* pOrderedAss)
{
	_orderedAss = pOrderedAss;
}

Vector<As*>* Topology::GetOrderedAssAfterInitialized()
{
	return _orderedAss;
}


void Topology::RunBgp()
{
	// First Loop - Base Case
	// Each AS introduce himself to his neighbors
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		(static_cast<As*>(Vertices[i]))->InitialIntroduceMyselfToNeighbors();
	}

	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		(static_cast<As*>(Vertices[i]))->_lastIterationUpdatedPaths.traverse();
	}

	// Regular Loop
	// Each AS only sends updates to his neighbors
	do
	{
		for (unsigned int i = 0; i < Vertices.size(); i++)
		{
			(static_cast<As*>(Vertices[i]))->BgpIteration();
		}
	} while (WasUpdateOnLastBgpIteration());
}

bool Topology::WasUpdateOnLastBgpIteration()
{
	bool wasUpdateOnIteration = false;
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		wasUpdateOnIteration |= (static_cast<As*>(Vertices[i]))->WasUpdateOnSelectedPaths;
	}

	// After checking whether there was an update in the last iteration, nullify it to the next iteration.
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		(static_cast<As*>(Vertices[i]))->WasUpdateOnSelectedPaths = false;
	}
	return wasUpdateOnIteration;
}

void Topology::PrintGraph()
{
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		(static_cast<As*>(Vertices[i]))->PrintEdges();
	}
}

#include <iostream>
void Topology::PrintSelectedaPaths()
{
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		As* node = static_cast<As*>(Vertices[i]);
		Map<As*, Vector<As*> > selectedPaths = node->GetSelectedPaths();
		std::cout << node->GetName() << ": " << std::endl;

		//auto x = selectedPaths.begin()->second;
		//x.find(node);

		for (Map<As*, Vector<As*> >::iterator mapIter = selectedPaths.begin(); mapIter != selectedPaths.end(); ++mapIter)
		{
			As* to = mapIter->first;
			Vector<As*> path = mapIter->second;
			std::cout << "The way to - " << mapIter->first->GetName() << ", Is through the Selected Path: ";
			for (Vector<As*>::iterator hopsIter = path.begin(); hopsIter != path.end(); ++hopsIter)
			{
				As* hop = *hopsIter;
				std::cout << hop->GetName() << ' ';
			}
			std::cout << std::endl;
		}
		std::cout << std::endl;
	}
}


int Topology::HowMuchTrafficThroughTheAttacker(As* pAttacker, As* pVictim)
{
	int numberOfPaths = 0;
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		As* node = static_cast<As*>(Vertices[i]);
		if (node == pAttacker)
		{
			// Dont count the attacker own paths
			continue;
		}

		Map<As*, Vector<As*> > selectedPaths = node->GetSelectedPaths();

		for (Map<As*, Vector<As*> >::iterator mapIter = selectedPaths.begin(); mapIter != selectedPaths.end(); ++mapIter)
		{
			As* to = mapIter->first;
			Vector<As*> path = mapIter->second;

			if (pVictim == 0)
			{
				numberOfPaths = (path.find(path.begin(), path.end(), pAttacker) != path.end()) ?
					(numberOfPaths + 1) : numberOfPaths;
			}
			else
			{
				numberOfPaths = (to == pVictim) && (path.find(path.begin(), path.end(), pAttacker) != path.end()) ?
					(numberOfPaths + 1) : numberOfPaths;
			}
		}
	}
	return numberOfPaths;
}

void Topology::NullifyBgp()
{
	for (unsigned int i = 0; i < Vertices.size(); i++)
	{
		As* node = static_cast<As*>(Vertices[i]);
		node->NullifyBgp();
	}
}

